using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace Nirvana
{
    public enum ResLoadState
    {
        /// <summary>
        /// 未加载资源
        /// </summary>
        UnLoad,

        /// <summary>
        /// 正在加载资源中
        /// </summary>
        Loading,

        /// <summary>
        /// 已加载完资源
        /// </summary>
        Loaded,
    }

    public enum ActionState
    {
        /// <summary>
        /// 显示
        /// </summary>
        Load,

        /// <summary>
        /// 不显示
        /// </summary>
        UnLoad,
        Nothing,
    }

    public static class BigWorldHelper
    {
        /// <summary>
        /// Mesh块的大小
        /// </summary>
        public static readonly int MeshBlockRange = 20;

        /// <summary>
        /// 近距离mesh距离
        /// </summary>
        public static float SmallMesh = 5.0f;

        /// <summary>
        /// 中等mesh距离
        /// </summary>
        public static float MiddleMesh = 5.0f;

        /// <summary>
        /// 最远mesh距离
        /// </summary>
        public static float LargeMesh = 5.0f;

        public static float Small = SmallMesh * SmallMesh;
        public static float Middle = MiddleMesh * MiddleMesh;
        public static float Large = LargeMesh * LargeMesh;

        /// <summary>
        /// mesh超过就不显示
        /// </summary>
        public static float MeshCullDistance = 200f;

        /// <summary>
        /// 在这个范围内的mesh直接显式，不计算屏占比
        /// </summary>
        public static float MeshNearDistance = 15f * 15f;

        /// <summary>
        /// mesh显示区间
        /// </summary>
        public static float AppearValue = 0.0041f;

        /// <summary>
        /// mesh消失区间
        /// </summary>
        public static float DisappearValue = 0.0040f;

        /// <summary>
        /// 显示mesh块的数量(边长)
        /// </summary>
        public static int MeshBlockCount = 7;

        private static Vector3 _cameraPos;
        private static Vector3 _playerPos;

        /// <summary>
        /// 工具类中记录玩家位置和相机位置，方便计算
        /// </summary>
        /// <param name="cameraPos"></param>
        /// <param name="playerPos"></param>
        public static void SetPos(ref Vector3 cameraPos, ref Vector3 playerPos)
        {
            _cameraPos = cameraPos;
            _playerPos = playerPos;
        }

        #region 扩展方法

        /// <summary>
        /// 扩展Vector3的二进制写入
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="v"></param>
        public static void Write(this BinaryWriter writer, Vector3 v)
        {
            writer.Write(v.x);
            writer.Write(v.y);
            writer.Write(v.z);
        }

        /// <summary>
        /// 扩展Vector4的二进制写入
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="v"></param>
        public static void Write(this BinaryWriter writer, Vector4 v)
        {
            writer.Write(v.x);
            writer.Write(v.y);
            writer.Write(v.z);
            writer.Write(v.w);
        }

        /// <summary>
        /// 扩展Color的二进制写入
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="color"></param>
        public static void Write(this BinaryWriter writer, Color color)
        {
            writer.Write(color.r);
            writer.Write(color.g);
            writer.Write(color.b);
            writer.Write(color.a);
        }

        /// <summary>
        /// 从二进制文件中读取Vector3
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static Vector3 ReadVector3(this BinaryReader reader)
        {
            return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
        }

        /// <summary>
        /// 从二进制文件中读取Vector4
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static Vector4 ReadVector4(this BinaryReader reader)
        {
            return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
        }

        /// <summary>
        /// 从二进制文件中读取Color
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static Color ReadColor(this BinaryReader reader)
        {
            return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
        }

        public static T GetOrAddComponent<T>(this GameObject obj) where T : Component
        {
            T component = obj.GetComponent<T>();
            if (component == null)
            {
                component = obj.AddComponent<T>();
            }

            return component;
        }

        public static T GetOrAddComponent<T>(this Component component) where T : Component
        {
            return component.gameObject.GetOrAddComponent<T>();
        }

        #endregion

        public static void WriteDatas<T>(BinaryWriter writer, ref T[] datas) where T : class, IBigWorldIO
        {
            if (datas != null)
            {
                int count = datas.Length;
                writer.Write(count);
                for (int i = 0; i < count; i++)
                {
                    datas[i].Write(writer);
                }
            }
            else
            {
                writer.Write(0);
            }
        }

        public static void ReadDatas<T>(BinaryReader reader, ref T[] datas) where T : class, IBigWorldIO
        {
            int count = reader.ReadInt32();
            datas = new T[count];
            for (int i = 0; i < count; i++)
            {
                T node = Activator.CreateInstance<T>();
                node.Read(reader);
                datas[i] = node;
            }
        }

        /// <summary>
        /// 计算mesh是否显示
        /// </summary>
        /// <param name="objPos"></param>
        /// <param name="meshRadius"></param>
        /// <returns></returns>
        public static ActionState CalcProjectSize(ref Vector3 objPos, ref float meshRadius)
        {
            // 小于MeshNearDistance不计算屏占比，直接显示
            if ((_playerPos - objPos).sqrMagnitude < MeshNearDistance) return ActionState.Load;
            // 计算相机到物体的距离与物体半径+最大显式距离，如果超过物体半径+最大显示距离则不显示mesh
            Vector3 offset = _cameraPos - objPos;
            float offsetSqrMagnitude = offset.sqrMagnitude;
            float meshReadlyDistance = meshRadius + MeshCullDistance;
            if (offsetSqrMagnitude > meshReadlyDistance * meshReadlyDistance)
            {
                return ActionState.UnLoad;
            }

            return ActionState.Load;
        }

        public static ActionState CalcProjectSize(ref Vector4 surfaceArea, ref Vector3 objPos, ref float meshRadius)
        {
            // 小于MeshNearDistance不计算屏占比，直接显示
            if ((_playerPos - objPos).sqrMagnitude < MeshNearDistance) return ActionState.Load;
            Vector3 offset = _cameraPos - objPos;
            float offsetSqrMagnitude = offset.sqrMagnitude;
            float meshReadlyDistance = meshRadius + MeshCullDistance;
            if (offsetSqrMagnitude > meshReadlyDistance * meshReadlyDistance)
            {
                return ActionState.UnLoad;
            }

            Vector3 dir = offset.normalized;
            float dir_x = dir.x * surfaceArea.x;
            float dir_y = dir.y * surfaceArea.y;
            float dir_z = dir.z * surfaceArea.z;
            float surface_val = Mathf.Abs(dir_x) + Mathf.Abs(dir_y) + Mathf.Abs(dir_z) + surfaceArea.w;
            float ret = surface_val * (1f / offsetSqrMagnitude);
            if (ret > AppearValue) return ActionState.Load;
            if (ret < DisappearValue) return ActionState.UnLoad;
            return ActionState.Nothing;
        }

        public static void LoadAll<T>(List<T> list) where T : IBigWorldLoad
        {
            if (list == null) return;
            for (int i = 0; i < list.Count; i++)
            {
                T loader = list[i];
                if (loader != null)
                {
                    loader.Load();
                }
            }
        }

        public static void UnLoadAll<T>(List<T> list) where T : IBigWorldLoad
        {
            if (list == null) return;
            for (int i = 0; i < list.Count; i++)
            {
                T loader = list[i];
                if (loader != null)
                {
                    loader.UnLoad();
                }
            }
        }
    }
}